﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Luna;

namespace TextDataExtractor.DEML {
	
	public class CompositePattern : AbstractPattern {

		public IEnumerable<AbstractPattern> SubPatterns { get { return getChildren<AbstractPattern>(); } }

		protected override void processChildNode(System.Xml.XmlNode child, DemlRegistry registry) {
			if (DemlFactory.Instance.isElementType(ElementType.Pattern, child.Name)) {
				AbstractPattern pattern = (AbstractPattern)DemlFactory.Instance.createElement(ElementType.Pattern, child.Name);
				if (pattern != null) {
					pattern.loadFromXml(child, registry);
					int minOccur = pattern.getArgument("minoccur").toInt(1);
					int maxOccur = pattern.getArgument("maxoccur").Equals("n") ? int.MaxValue : pattern.getArgument("maxoccur").toInt(1);
					if (!(pattern is InclusionPattern) && (minOccur != 1 || maxOccur != 1 )) {
						InclusionPattern p = new InclusionPattern(pattern, minOccur, maxOccur);
						pattern = p;
					}
					Children.Add(pattern);
				}
			}
			else base.processChildNode(child, registry);
		}

		public bool RandomOrder {
			get { return getArgument("order").CompareTo("random") == 0; }
		}

		public override int match(string input) {
			int sidx = 0, result = 0;
			IsSuccess = true;

			StartIndex = int.MaxValue;
			EndIndex = 0;

			foreach (AbstractPattern pattern in SubPatterns) {
				if (RandomOrder) sidx = 0;
				int matchresult = pattern.match(sidx >= 0 ? (sidx < input.Length ? input.Substring(sidx) : string.Empty) : input);
				if (matchresult <= 0) {
					IsSuccess = false;
					break;
				}
				StartIndex = Math.Min(StartIndex, sidx + pattern.StartIndex);
				EndIndex = Math.Max(EndIndex, sidx + pattern.EndIndex);
				result += matchresult;

				sidx = pattern.EndIndex + 1;
			}
			return IsSuccess ? result + 1 : 0;
		}

		public override IEnumerable<AbstractPattern> getMatchedPatterns(Predicate<AbstractPattern> pred) {
			if (IsSuccess) {
				foreach (AbstractPattern p in SubPatterns) {
					foreach (AbstractPattern c in p.getMatchedPatterns(pred))
						yield return c;
				}
			}
		}

		public override string getMatchedPatternName(int indent) {
			if (IsSuccess) {
				StringBuilder b = new StringBuilder();
				b.Append(new string('\t', indent));
				b.Append(Name);
				b.AppendLine("[");
				foreach (var pattern in SubPatterns) {
					b.AppendLine(pattern.getMatchedPatternName(indent + 1));
				}
				b.Append(new string('\t', indent));
				b.Append("]");
				return b.ToString();
			}
			return string.Empty;
		}
	}
}
